package downstream

import (
	"context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/status"
	"inventory/api/inventory"
	"inventory/api/prod"
	"inventory/internal/conf"
	"inventory/internal/constant"
	"inventory/internal/model"
	"inventory/pkg/ecode"
	"inventory/pkg/log"
	"inventory/pkg/network"
	"inventory/pkg/request_key"
	"time"
)

func newProdClient(ctx context.Context, addr string) (
	client prod.ProdClient, err error) {
	var conn *grpc.ClientConn
	conn, err = grpc.Dial(addr, grpc.WithInsecure(),
		grpc.WithUnaryInterceptor(network.ClientInterceptor(
			"bilin_prod", time.Second*3, prodErrorTranslator)))
	if err != nil {
		err = ecode.AppendMessage(constant.ErrRemoteAPIFailed, "商品中心服务地址无法建立有效连接, err=%s", err.Error())
		log.FromContext(ctx).Warnw(err.Error())
		return
	}
	client = prod.NewProdClient(conn)
	return
}

func prodErrorTranslator(err error) (errCode *ecode.ErrorCode) {
	rpcStatus := status.Convert(err)
	for _, detail := range rpcStatus.Details() {
		switch t := detail.(type) {
		case *prod.DefaultResp:
			errCode = ecode.NewError(t.ErrorCode, t.ErrorMessage, ecode.ErrorType{
				GRPCCode: rpcStatus.Code(),
				ErrType:  t.ErrorType,
			})
			return
		}
	}
	errCode = ecode.AppendMessage(
		constant.ErrRemoteAPIFailed, "商品中心服务系统错误，请稍后再试")
	return
}

// FetchProductTypes 获取商品类型
func (d *Downstream) FetchProductTypes(ctx context.Context, empId, sgId uint32, productTypeIds []uint32) (
	views []*inventory.WarehouseStorageType, err error) {
	if d.prodClient == nil {
		if d.prodClient, err = newProdClient(ctx, conf.Conf.Downstream.ProdURL); err != nil {
			return
		}
	}
	reqIds := make([]uint32, len(productTypeIds))
	for i, prodTypeId := range productTypeIds {
		reqIds[i] = prodTypeId
	}
	var resp *prod.SelectionProdTypesResponse
	clientCtx, cancel := request_key.NewOutGoingContext(ctx, time.Second*3)
	defer cancel()
	if resp, err = d.prodClient.SelectionProdTypes(
		clientCtx,
		&prod.SelectionProdTypesRequest{
			Token: &prod.WebToken{
				EmpId: empId,
				SgId:  sgId,
			},
			PStoreId: 0,
			Ids:      reqIds,
		}); err != nil {
		return
	} else {
		for _, obj := range resp.ProdTypes {
			views = append(views, &inventory.WarehouseStorageType{
				Id:   obj.Id,
				Name: obj.Name,
			})
		}
	}
	return
}

// FetchObjects 查看商品库指定类别对象信息列表
func (d *Downstream) FetchObjects(ctx context.Context, sgId uint32, objectKeys []string) (
	objects []*prod.SelectionObjectView, err error) {
	var resp *prod.SelectionObjectListResponse
	if d.prodClient == nil {
		if d.prodClient, err = newProdClient(ctx, conf.Conf.Downstream.ProdURL); err != nil {
			return
		}
	}
	clientCtx, cancel := request_key.NewOutGoingContext(ctx, time.Second*3)
	defer cancel()
	if resp, err = d.prodClient.SelectionObjectList(clientCtx, &prod.SelectionObjectListRequest{
		SgId:       sgId,
		ObjectKeys: objectKeys,
	}); err != nil {
		return
	}
	objects = resp.Objects
	return
}

// FetchCommonProds 获取商品
func (d *Downstream) FetchCommonProds(ctx context.Context, sgId uint32, prodIDs []uint64) (
	views []*prod.SelectionProdView, err error) {
	reqIds := make([]uint64, len(prodIDs))
	for i, prodId := range prodIDs {
		reqIds[i] = prodId
	}
	var resp *prod.SelectionProdsFullResponse
	if d.prodClient == nil {
		if d.prodClient, err = newProdClient(ctx, conf.Conf.Downstream.ProdURL); err != nil {
			return
		}
	}
	clientCtx, cancel := request_key.NewOutGoingContext(ctx, time.Second*3)
	defer cancel()
	if resp, err = d.prodClient.SelectionProdsFull(clientCtx, &prod.SelectionProdListRequest{
		SgId: sgId,
		Ids:  reqIds,
	}); err != nil {
		return
	} else {
		views = resp.Prods
	}
	return
}

// UpdateProductBom 更新商品bom
func (d *Downstream) UpdateProductBom(ctx context.Context, sgId, pStoreID uint32, prodID, SkuID uint64, isConfigured bool) (err error) {
	return
}

// FetchProductBom 获取商品bom
func (d *Downstream) FetchProductBom(ctx context.Context, sgId, pStoreID, fetchStoreID, pageNo, pageSize, isConfigured,
	prodNature, fetchMode uint32, query string, inProdIDs []int) (total int64, views []*inventory.ProdBomView, err error) {
	return
}

// BuildObjectRemarks 构造商品、加料remark记录表
func (d *Downstream) BuildObjectRemarks(ctx context.Context, sgId uint32, ids []string) (map[string]*model.FullRemark, error) {
	if len(ids) == 0 {
		return nil, nil
	}
	objects, err := d.FetchObjects(ctx, sgId, ids)
	if err != nil {
		return nil, err
	}
	remarks := make(map[string]*model.FullRemark)
	for _, o := range objects {
		remarks[o.Id] = &model.FullRemark{
			SnapShotRemark: model.SnapShotRemark{
				Type: o.TypeName,
				Remark: model.Remark{
					Code:    o.Id,
					Name:    o.Name,
					SkuName: o.SkuName,
					Unit:    o.Unit,
				},
			},
			PurchaseRatio: 1,
			PurchaseUnit:  o.Unit,
			StorageRatio:  1,
			StorageUnit:   o.Unit,
			TypeID:        o.TypeId,
			PStoreID:      o.PStoreId,
		}
	}
	return remarks, nil
}
